/**
 * Generali Solutions d'assurances - Tous droits réservés &copy; 2007 - 2010
 */
package fr.generali.accueilclient.ref.bancaire.services.impl;

import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Service;

import fr.generali.accueilclient.banque.builder.BanqueGestionnaireBuilder;
import fr.generali.accueilclient.banque.om.IBanqueGestionnaire;
import fr.generali.accueilclient.client.om.IContact;
import fr.generali.accueilclient.client.om.IContratsRib;
import fr.generali.accueilclient.client.om.ICoordonneeBancaire;
import fr.generali.accueilclient.client.om.NaturePersonne;
import fr.generali.accueilclient.commun.exception.AccueilClientBusinessException;
import fr.generali.accueilclient.commun.exception.AccueilClientModificationContactException;
import fr.generali.accueilclient.commun.exception.AccueilClientTechnicalException;
import fr.generali.accueilclient.ref.bancaire.services.IRefBancaireService;
import fr.generali.accueilclient.utils.code.error.ControleIBANCodeError;
import fr.generali.refservcommuns.rce.autresreferentiels.refbancaire.services.IRefBancaireWebService;
import fr.generali.refservcommuns.rce.autresreferentiels.refbancaire.demande.DtoDemandeIban;
import fr.generali.refservcommuns.rce.autresreferentiels.refbancaire.pty.gestionrolesmetier.DtoBanque;
import fr.generali.refservcommuns.rce.autresreferentiels.refbancaire.pty.modelemetier.pivot.DtoCompteBancaireIban;
import fr.generali.refservcommuns.rce.autresreferentiels.refbancaire.reponse.DtoReponseIban;
import fr.generali.refservcommuns.rce.autresreferentiels.refbancaire.technique.DtoResult;
import fr.generali.refservcommuns.rce.desactivation.desactivationservice.Desactivation;
import fr.generali.refservcommuns.rce.desactivation.services.IDesactivationWebService;
import fr.generali.refservcommuns.rce.gestionbancaire.dtogestionbancaire.DtoDossierP16;
import fr.generali.refservcommuns.rce.gestionbancaire.dtogestionbancaire.DtoListeDossierP16;
import fr.generali.refservcommuns.rce.gestionbancaire.gestionbancaireservice.GestionBancaire;
import fr.generali.refservcommuns.rce.servperscom.pty.referencebancaire.DtoCompteBancaire;
import fr.generali.refservcommuns.rce.gestionbancaire.gestionbancaireservice.GestionBancaireResponse;
import fr.generali.refservcommuns.rce.gestionbancaire.services.IGestionBancaireWebService;
import fr.generali.refservcommuns.rce.gestionbancaire.services.WsRceBusinessException;
import fr.generali.refservcommuns.rce.majliens.MajLiensClientsAdrRib;
import fr.generali.refservcommuns.rce.majliens.MajLiensClientsAdrRibResponse;
import fr.generali.refservcommuns.rce.majliens.services.MajLiensClientsAdrRibWebService;
import fr.generali.refservcommuns.rce.majliens.services.ResumeWSBusinessException;
import fr.generali.refservcommuns.rce.majliens.services.TechnicalFault;
import fr.generali.refservcommuns.rce.majliens.out.DtoDossierRibOut;
import fr.generali.refservcommuns.rce.majliens.out.DtoListeDossierS22Out;
import fr.generali.refservcommuns.rce.majliens.out.DtoListeRibOut;

/**
 * Implémentation de {@link IRefBancaireService}
 * 
 * @author selrhazala
 */
@Service
public class RefBancaireService implements IRefBancaireService {

    /**
     * LOGGER
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(RefBancaireService.class);

    /**
     * Service de gestion bancaire
     */
    @Autowired
    @Qualifier("P16")
    private IGestionBancaireWebService p16;

    /**
     * Service de controle de références bancaires
     */
    @Autowired
    @Qualifier("controlerRib")
    private IRefBancaireWebService checkRib;

    /**
     * Service de désactivation contact et rib
     */
    @Autowired
    @Qualifier("P18")
    private IDesactivationWebService p18;

    /**
     * Service de réaffectation de rib
     */
    @Autowired
    @Qualifier("S22")
    private MajLiensClientsAdrRibWebService s22;

    /**
     * Assembler en entrée de P16
     */
    @Autowired
    @Qualifier("contactToGestionBancaireConverter")
    private Converter<IContact, GestionBancaire> contactToGestionBancaireConverter;

    /**
     * Assembler en entrée de P16 Pro
     */
    @Autowired
    @Qualifier("contactProToGestionBancaireConverter")
    private Converter<IContact, GestionBancaire> contactProToGestionBancaireConverter;

    /**
     * Assembler en entrée de P18
     */
    @Autowired
    @Qualifier("contactToDesactivationContactConverter")
    private Converter<IContact, Desactivation> contactToDesactivationContactConverter;

    /**
     * Assembler en entrée de P18 Pro
     */
    @Autowired
    @Qualifier("contactProToDesactivationContactConverter")
    private Converter<IContact, Desactivation> contactProToDesactivationContactConverter;

    /**
     * Assembler en entrée de controleRib
     */
    @Autowired
    @Qualifier("iban2toDtoDemandeIbanConverter")
    private Converter<String, DtoDemandeIban> iban2toDtoDemandeIbanConverter;

    /**
     * Assembler en entrée de S22
     */
    @Autowired
    @Qualifier("contratsRibToMajLiensClientsAdrRibConverter")
    private Converter<IContratsRib, MajLiensClientsAdrRib> contratsRibToMajLiensClientsAdrRibConverter;

    /**
     * {@inheritDoc}
     */
    public ICoordonneeBancaire gererRib(IContact contact) throws AccueilClientBusinessException {
        GestionBancaireResponse gestionBancaireResponse = null;

        try {
            gestionBancaireResponse = p16.gestionBancaire(contactToGestionBancaireConverter.convert(contact));

            // Si le client est un pro, nous devons également créé le rib dans
            // sa sphère professionnelles
            if (contact != null && contact.getClient() != null
                            && NaturePersonne.PROFESSIONNEL.equals(contact.getClient().getNaturePersonne())) {
                p16.gestionBancaire(contactProToGestionBancaireConverter.convert(contact));
            }
        } catch (fr.generali.refservcommuns.rce.gestionbancaire.services.TechnicalFault e) {
            LOGGER.error(e.getMessage());
            throw new AccueilClientTechnicalException(e.getMessage(), StringUtils.EMPTY, e);
        } catch (WsRceBusinessException e) {
            LOGGER.error(e.getMessage());
            throw new AccueilClientBusinessException(e.getMessage(), e);
        }

        return getIdentifiantRibResponse(gestionBancaireResponse, contact);
    }

    /**
     * @param gestionBancaireResponse la réponse retournée par le WS
     * @param contact le contact
     * @return idRetour String
     */
    private ICoordonneeBancaire getIdentifiantRibResponse(GestionBancaireResponse gestionBancaireResponse,
                    IContact contact) {
        ICoordonneeBancaire ribRetour = null;

        if (gestionBancaireResponse != null) {
            DtoListeDossierP16 listeDossierCB = gestionBancaireResponse.getDtoListeDossierP16();
            if (listeDossierCB != null) {
                List<DtoDossierP16> listeDossierP16 = listeDossierCB.getDossierP16();
                if (CollectionUtils.isNotEmpty(listeDossierP16)) {
                    DtoDossierP16 dossierP16 = listeDossierP16.get(0);
                    if (dossierP16 != null) {
                        ribRetour = contact.getCoordonneeBancaire();
                        if (dossierP16.getCompteBancairePrincipal() != null) {
                            DtoCompteBancaire compteBancaire = dossierP16.getCompteBancairePrincipal();
                            StringBuffer bfNumOrdre = new StringBuffer();

                            if (StringUtils.isNotEmpty(compteBancaire.getNumOrdre())
                                            && compteBancaire.getNumOrdre().length() < 2
                                            && Integer.valueOf(compteBancaire.getNumOrdre()) < 10) {
                                bfNumOrdre.append("0");
                            }

                            bfNumOrdre.append(compteBancaire.getNumOrdre());

                            ribRetour.setNumOrdre(bfNumOrdre.toString());
                            ribRetour.setIdentifiant(compteBancaire.getIdentifiant());
                        } else if (dossierP16.getCompteBancaireSecondaire() != null) {
                            List<DtoCompteBancaire> listeCompteBancaire = dossierP16.getCompteBancaireSecondaire();
                            if (CollectionUtils.isNotEmpty(listeCompteBancaire)) {
                                DtoCompteBancaire compteBancaire = listeCompteBancaire.get(0);
                                StringBuffer bfNumOrdre = new StringBuffer();

                                if (StringUtils.isNotEmpty(compteBancaire.getNumOrdre())
                                                && compteBancaire.getNumOrdre().length() < 2
                                                && Integer.valueOf(compteBancaire.getNumOrdre()) < 10) {
                                    bfNumOrdre.append("0");
                                }

                                bfNumOrdre.append(compteBancaire.getNumOrdre());

                                ribRetour.setNumOrdre(bfNumOrdre.toString());
                                ribRetour.setIdentifiant(compteBancaire.getIdentifiant());
                            }
                        }
                    }
                }
            }
        }

        return ribRetour;
    }

    /**
     * {@inheritDoc}
     */
    public String affecterRib(IContratsRib contratsRib) throws AccueilClientBusinessException {
        MajLiensClientsAdrRibResponse majRibResponse = null;

        try {
            majRibResponse =
                            s22.majLiensClientsAdrRib(contratsRibToMajLiensClientsAdrRibConverter.convert(contratsRib));
        } catch (ResumeWSBusinessException e) {
            LOGGER.error(e.getMessage());
            throw new AccueilClientModificationContactException(e.getMessage(), StringUtils.EMPTY, e);
        } catch (TechnicalFault e) {
            LOGGER.error(e.getMessage());
            throw new AccueilClientModificationContactException(e.getMessage(), StringUtils.EMPTY, e);
        }

        return getRetourAffectation(majRibResponse);
    }

    /**
     * @param majRibResponse la réponse retournée par le WS
     * @return idRetour String
     */
    private String getRetourAffectation(MajLiensClientsAdrRibResponse majRibResponse) {
        String idRetour = StringUtils.EMPTY;

        if (majRibResponse != null) {
            DtoListeDossierS22Out listeDossierS22Out = majRibResponse.getDtoListeDossierS22Out();
            if (listeDossierS22Out != null) {
                DtoListeRibOut listeRibOut = listeDossierS22Out.getListeDossierRibOut();
                if (listeRibOut != null) {
                    List<DtoDossierRibOut> listeDossierRibOut = listeRibOut.getDossierRibOut();
                    if (CollectionUtils.isNotEmpty(listeDossierRibOut)) {
                        DtoDossierRibOut dossierRibOut = listeDossierRibOut.get(0);
                        if (dossierRibOut != null) {
                            if (dossierRibOut.getCodeRetour() != null) {
                                idRetour = dossierRibOut.getCodeRetour();
                            }
                        }
                    }
                }
            }
        }

        return idRetour;
    }

    /**
     * {@inheritDoc}
     */
    public void desactiverRib(IContact contact) throws AccueilClientBusinessException {
        try {
            p18.desactivation(contactToDesactivationContactConverter.convert(contact));
            // Si le client est un pro, nous devons également créé le rib dans
            // sa sphère professionnelles
            if (contact != null && contact.getClient() != null
                            && NaturePersonne.PROFESSIONNEL.equals(contact.getClient().getNaturePersonne())) {
                p18.desactivation(contactProToDesactivationContactConverter.convert(contact));
            }
        } catch (fr.generali.refservcommuns.rce.desactivation.services.TechnicalFault e) {
            LOGGER.error(e.getMessage());
            throw new AccueilClientModificationContactException(e.getMessage(), StringUtils.EMPTY, e);
        } catch (fr.generali.refservcommuns.rce.desactivation.services.WsRceBusinessException e) {
            LOGGER.error(e.getMessage());
            throw new AccueilClientModificationContactException(e.getMessage(), StringUtils.EMPTY, e);
        }
    }

    /**
     * {@inheritDoc}
     */
    public Map<ControleIBANCodeError, IBanqueGestionnaire> controleIBAN(String iban) {

        DtoReponseIban dtoReponseIban = checkRib.controleIBAN(iban2toDtoDemandeIbanConverter.convert(iban));

        Map<ControleIBANCodeError, IBanqueGestionnaire> mapBanqueGestionnaire = MapUtils.EMPTY_MAP;

        if (dtoReponseIban != null) {

            DtoResult resultIban = dtoReponseIban.getResultIban();

            if (resultIban != null
                            && BigInteger.valueOf(ControleIBANCodeError.CODE_ERROR_00.getCode().longValue()).equals(
                                            resultIban.getCodeRetour())) {

                mapBanqueGestionnaire = fillMapGestionBancaire(dtoReponseIban, resultIban);
            }

            else if (resultIban != null
                            && !BigInteger.valueOf(ControleIBANCodeError.CODE_ERROR_00.getCode().longValue()).equals(
                                            resultIban.getCodeRetour())) {
                mapBanqueGestionnaire = fillMapGestionBancaire(dtoReponseIban, resultIban);
            }
        }

        return mapBanqueGestionnaire;

    }

    /**
     * @param dtoReponseIban reponse iban
     * @param resultIban result iban
     * @return map gestion bancaire
     */
    private Map<ControleIBANCodeError, IBanqueGestionnaire> fillMapGestionBancaire(DtoReponseIban dtoReponseIban,
                    DtoResult resultIban) {

        Map<ControleIBANCodeError, IBanqueGestionnaire> mapBanqueGestionnaire =
                        new HashMap<ControleIBANCodeError, IBanqueGestionnaire>(0);

        DtoCompteBancaireIban compteBancaireIban = dtoReponseIban.getCompteBancaireIban();
        DtoBanque banqueGestionnaire = compteBancaireIban == null ? null : compteBancaireIban.getBanqueGestionnaire();
        BanqueGestionnaireBuilder banqueGestionnaireBuilder = BanqueGestionnaireBuilder.banqueGestionnaire();

        if (compteBancaireIban != null && banqueGestionnaire != null) {

            banqueGestionnaireBuilder.buildCodeBIC(banqueGestionnaire.getCodeBIC());
            banqueGestionnaireBuilder.buildDomiciliation(banqueGestionnaire.getDomiciliation());

            MapUtils.safeAddToMap(mapBanqueGestionnaire,
                            ControleIBANCodeError.getControleIBAN(resultIban.getCodeRetour()),
                            banqueGestionnaireBuilder.build());

        }

        else {
            MapUtils.safeAddToMap(mapBanqueGestionnaire,
                            ControleIBANCodeError.getControleIBAN(resultIban.getCodeRetour()),
                            banqueGestionnaireBuilder.build());
        }

        return mapBanqueGestionnaire;
    }

}
